package com.guangwei.arithmetictest;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.security.Key;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;


public class TestUI extends AppCompatActivity implements View.OnClickListener{
    private static final String TAG = "Arithmetic TestUI";

    private TextView tvStatus;
    private Button btnCommit;
    private EditText etInputResult;

    private final int MSG_TIME = 0;
    private Timer mTimer = new Timer();
    private TimerTask mTask;
    private int mTimes = 0;
    private Handler handler;

    private Integer mTotalQuality = 100;
    private Integer mRemainTest = mTotalQuality;
    private Integer mMaxValue = 100;
    private Boolean mIsAddEnable = true;
    private Boolean mIsSubEnable = true;
    private Boolean mIsMulEnable = false;
    private Boolean mIsDivEnable = false;

    private static Random rand = new Random();
    private Integer[] mOp1List;
    private Integer[] mOp2List;
    private Integer[] mOperatorList; // 0 for add; 1 for sub; 2 for multiplication
    private Integer[] mResultList;
    private Integer mQuestionIndex = 0;
    private Integer mCountCorrect = 0;
    private Integer mCountWrong = 0;
    private long mStartTestTime = 0;
    private String mTimeStamp;

    private static final String FILE_FOLDER =
            Environment.getExternalStorageDirectory().getAbsolutePath()
                    + File.separator + "ArithmeticTest" + File.separator + "data";
    private static final String SUMMARY_CSV = "summary.csv";
    private static final String DETAIL_CSV = "detail.csv";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_ui);

        Intent intent = getIntent();
        Bundle bd = intent.getExtras();
        mTotalQuality = bd.getInt("TotalQuality", 50);
        mMaxValue = bd.getInt("MaxValue", 100);
        mIsAddEnable = bd.getBoolean("IsAddEnable", true);
        mIsSubEnable = bd.getBoolean("IsSubEnable", true);
        mIsMulEnable = bd.getBoolean("IsMulEnable", false);
        mIsDivEnable = bd.getBoolean("IsDivEnable", false);
        Log.i(TAG, String.format("totalQuality=%d,  maxValue=%d,  isAddEnable=%b,  isSubEnable=%b,  isMulEnable=%b", mTotalQuality, mMaxValue, mIsAddEnable, mIsSubEnable,mIsMulEnable));
        mRemainTest = mTotalQuality;

        tvStatus = findViewById(R.id.status);
        etInputResult = findViewById(R.id.et_input_result);
        btnCommit = findViewById(R.id.btn_commit);
        btnCommit.setOnClickListener(this);

        initialTimer();
        initArithmeticArray();
        getTimeStamp();
        //promptMsg();
        generateQuestion(mQuestionIndex);

        // 监听软键盘
        etInputResult.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_SEND) {
                    Log.i(TAG, "onEditorAction: IME_ACTION_SEND");
                    commitAnswer();
                    return true;
                }
                return false;
            }
        });

        // 监听蓝牙键盘
        etInputResult.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode==KeyEvent.KEYCODE_NUMPAD_ENTER && event.getAction() == KeyEvent.ACTION_UP){
                    Log.i(TAG, "onKey: 按下回车键");
                    commitAnswer();
                    return true;
                }
                return false;
            }
        });
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_commit:
                Log.i(TAG, "Press the commit button");
                commitAnswer();
                break;
            default:
                break;
        }
    }

    private void commitAnswer() {
        Log.i(TAG, "commitAnswer++");
        String strInputResult = etInputResult.getText().toString().trim();
        if (strInputResult.equals("")) {
            Toast.makeText(this, getText(R.string.input_format_error), Toast.LENGTH_LONG).show();
            return;
        }
        Integer inputResult = Integer.valueOf(strInputResult);
        String strStatus = "";
        String strStatusSpeak = "";
        if (inputResult == mResultList[mQuestionIndex]) {
            strStatusSpeak = "答对了，很棒喔！";
            strStatus = "Pass";
            mCountCorrect++;
        } else {
            strStatusSpeak = "答错了，加油！";
            strStatus = "Fail";
            mCountWrong++;
        }
        Log.i(TAG, strStatusSpeak);
        SystemTTS.getInstance(this).speak(strStatusSpeak);
        etInputResult.setText("");

        String strOperator = "+'";
        if (mOperatorList[mQuestionIndex] == 0) strOperator = "+";
        if (mOperatorList[mQuestionIndex] == 1) strOperator = "-";
        if (mOperatorList[mQuestionIndex] == 2) strOperator = "×";
        if (mOperatorList[mQuestionIndex] == 3) strOperator = "÷";
        String strQuestion = String.valueOf(mOp1List[mQuestionIndex]) + strOperator + String.valueOf(mOp2List[mQuestionIndex]);

        String strAnswer = String.valueOf(mResultList[mQuestionIndex]);

        long duration = System.currentTimeMillis() - mStartTestTime;
        String strDuration = String.valueOf((int)(duration/1000));
        String strRemark = "Keypad";

        String[] csvData = {mTimeStamp, strQuestion, strAnswer, strInputResult, strStatus, strDuration, strRemark};
        WriteData2CSVThread csvWriteThread = new WriteData2CSVThread(csvData, FILE_FOLDER, DETAIL_CSV);
        csvWriteThread.run();

        //ReadCSVThread csvReadThread = new ReadCSVThread(FILE_FOLDER, DETAIL_CSV);
        //csvReadThread.run();

        ++mQuestionIndex;
        mRemainTest = mTotalQuality - mQuestionIndex;
        if (mRemainTest > 0) {
            generateQuestion(mQuestionIndex);
        } else {
            hideKeyboard();
            //showResultDialog();
            updateSummaryCsvFile();
            launchTestResultActivity();
            TestUI.this.finish();
        }
    }

    private void getTimeStamp() {
        Date date = new Date();
        String strDateFormat = "yyyy-MM-dd HH:mm:ss";
        SimpleDateFormat sdf = new SimpleDateFormat(strDateFormat);
        mTimeStamp = sdf.format(date);
    }

    private void showResultDialog(){
        /* @setIcon 设置对话框图标
         * @setTitle 设置对话框标题
         * @setMessage 设置对话框消息提示
         * setXXX方法返回Dialog对象，因此可以链式设置属性
         */

        String strFinalResult = String.format(getString(R.string.result_content), mCountCorrect, mCountWrong, mTimes);
        SystemTTS.getInstance(this).speak(strFinalResult);

        final AlertDialog.Builder normalDialog = new AlertDialog.Builder(TestUI.this);
        //normalDialog.setIcon(R.drawable.icon_dialog);
        normalDialog.setTitle(getString(R.string.result_dialog_title));
        normalDialog.setMessage(strFinalResult);
        normalDialog.setPositiveButton(getString(R.string.result_ok),
        new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        TestUI.this.finish();
                    }
                });
        // 显示
        normalDialog.show();
    }

    public void updateSummaryCsvFile() {
        String strTotal = String.valueOf(mTotalQuality);
        String strCorrect = String.valueOf(mCountCorrect);
        String strError = String.valueOf(mCountWrong);
        String strTotalDuration = String.valueOf(mTimes);
        String strScore = String.valueOf((int)((mCountCorrect/mTotalQuality)*100));
        String strAvgDuration = String.valueOf((int)((mTimes/mTotalQuality)));
        String strRemark = "Keypad";

        String[] csvData = {mTimeStamp, strTotal, strCorrect, strError, strTotalDuration, strScore, strAvgDuration, strRemark};
        WriteData2CSVThread csvWriteThread = new WriteData2CSVThread(csvData, FILE_FOLDER, SUMMARY_CSV);
        csvWriteThread.run();

        //ReadCSVThread csvReadThread = new ReadCSVThread(FILE_FOLDER, SUMMARY_CSV);
        //csvReadThread.run();
    }


    @SuppressLint("HandlerLeak")
    public TestUI() {
        handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case MSG_TIME:
                        tvStatus.setText(String.format(getString(R.string.status), mTotalQuality, mRemainTest, mTimes));

                        break;
                    default:
                        break;
                }
            }

        };
    }


    private void initialTimer() {
        mTask = new TimerTask() {
            @Override
            public void run() {
                mTimes++;
                handler.sendEmptyMessage(MSG_TIME);
            }
        };
        mTimer.schedule(mTask, 1000, 1000);
    }

    private void initArithmeticArray() {
        mQuestionIndex = 0;
        mCountCorrect = 0;
        mCountWrong = 0;
        mTimes = 0;

        SystemTTS.getInstance(this).speak("请做好准备。");
        SystemTTS.getInstance(this).speak("算术运算测试开始。");

        //  初始化操作符号
        int i =0;
        mOperatorList = new Integer[mTotalQuality];
        while (i < mOperatorList.length) {
            if (mIsAddEnable && i < mOperatorList.length)   mOperatorList[i++] = 0;
            if (mIsSubEnable && i < mOperatorList.length)   mOperatorList[i++] = 1;
            if (mIsMulEnable && i < mOperatorList.length)   mOperatorList[i++] = 2;
            if (mIsDivEnable && i < mOperatorList.length)   mOperatorList[i++] = 3;
        }

        // 打乱数组顺序
        ArrayUtils.shuffle(mOperatorList);

        // 生成操作数1和操作数2
        mOp1List = new Integer[mTotalQuality];
        mOp2List = new Integer[mTotalQuality];
        mResultList = new Integer[mTotalQuality];
        for (i=0; i<mTotalQuality; i++) {
            Integer op1 = 1+rand.nextInt(mMaxValue-1);
            Integer op2 = 1+rand.nextInt(mMaxValue-1);
            Integer result = -1;
            // 加
            if (mOperatorList[i] == 0) result = op1 + op2;
            // 减
            if (mOperatorList[i] == 1) result = op1 - op2;
            // 乘
            if (mOperatorList[i] == 2) {
                // 其中一个数必须为个位数
                if (op1>10 && op2>10) {
                    --i;
                    continue;
                }
                // 1000以内的数，最大的乘法为其开方的值
                if (mMaxValue<=1000) {
                    int maxOpVale = (int)Math.sqrt(mMaxValue);
                    if (op1>maxOpVale|| op2>maxOpVale) {
                        --i;
                        continue;
                    }
                }
                result = op1 * op2;
            }
            //  除 （先计算出乘法的 操作数1、操作数2、结果，然后再把结果和操作数1互换）
            if (mOperatorList[i] == 3) {
                // 其中一个数必须为个位数
                if (op1>10 && op2>10) {
                    --i;
                    continue;
                }
                // 1000以内的数，最大的乘法为其开方的值
                if (mMaxValue<=1000) {
                    int maxOpVale = (int)Math.sqrt(mMaxValue);
                    if (op1>maxOpVale|| op2>maxOpVale) {
                        --i;
                        continue;
                    }
                }
                result = op1 * op2;

                // 转换成 除法 （把结果和操作数1互换）
                int tmp = op1;
                op1 = result;
                result = tmp;
            }

            //  skip the repeat question (only make the recent 6 questions are not same)
            Boolean isRepeat = false;
            int count = 0;
            for (int j=i-1; j>=0; j--) {
                count++;
                if (count > 5) break;
                if (op1==mOp1List[j] && op2==mOp2List[j] && result==mResultList[j]) {
                    isRepeat = true;
                    break;
                }
            }
            if (isRepeat) {
                --i;
                continue;
            }

            if (result < 0 || result > mMaxValue) {i--; continue;}
            mOp1List[i] = op1;
            mOp2List[i] = op2;
            mResultList[i] = result;
        }
    }

    private void generateQuestion(Integer index) {
        String strOperator = "";
        String strQuestion = "";
        if (mOperatorList[index] == 0)      strOperator = "加";
        if (mOperatorList[index] == 1)      strOperator = "减";
        if (mOperatorList[index] == 2)      strOperator = "乘";
        if (mOperatorList[index] == 3)      strOperator = "除";

        strQuestion = mOp1List[index].toString() + strOperator + mOp2List[index].toString();
        Log.i(TAG, strQuestion);
        SystemTTS.getInstance(this).speak(strQuestion);

        mStartTestTime = System.currentTimeMillis();

        etInputResult.requestFocus();
        Timer timer = new Timer(); //设置定时器
        timer.schedule(new TimerTask() {
            @Override
            public void run() { //弹出软键盘的代码
                InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.showSoftInput(etInputResult, InputMethodManager.RESULT_SHOWN);
                imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
            }
        }, 50); //设置50毫秒的时长
    }

    class WriteData2CSVThread extends Thread {
        String[] data;
        String fileName;
        String folder;
        StringBuilder sb;
        public WriteData2CSVThread(String[] data, String folder, String fileName) {
            this.data = data;
            this.folder = folder;
            this.fileName = fileName;
        }
        private void createFolder() {
            File fileDir = new File(folder);
            boolean hasDir = fileDir.exists();
            if (!hasDir) {
                fileDir.mkdirs();// 这里创建的是目录
            }
        }
        @Override
        public void run() {
            super.run();
            createFolder();
            File eFile = new File(folder + File.separator + fileName);
            if (!eFile.exists()) {
                try {
                    boolean newFile = eFile.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            try {
                FileOutputStream os = new FileOutputStream(eFile, true);
                sb = new StringBuilder();
                for (int i = 0; i < data.length; i++) {
                    sb.append(data[i]).append(",");
                }
                sb.append("\n");
                os.write(sb.toString().getBytes());
                os.flush();
                os.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    class ReadCSVThread extends Thread {
        String fileName;
        String folder;
        public ReadCSVThread(String folder, String fileName) {
            this.folder = folder;
            this.fileName = fileName;
        }
        @Override
        public void run() {
            super.run();
            File inFile = new File(folder + File.separator + fileName);
            final StringBuilder cSb = new StringBuilder();
            String inString;
            try {
                BufferedReader reader =
                        new BufferedReader(new FileReader(inFile));
                while ((inString = reader.readLine()) != null) {
                    cSb.append(inString).append("\n");
                }
                reader.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    //mCSVTv.setText(cSb.toString());// 显示
                    Log.i(TAG, cSb.toString());
                }
            });
        }
    }

    public void launchTestResultActivity() {
        Intent intent = new Intent();
        intent.setAction("score_result_action");
        intent.addCategory("score_result_category");
        Bundle bd = new Bundle();

        int minutes = mTimes/60;
        int seconds = 0;
        String strFinalScore = "";
        if (minutes > 0) {
            seconds = mTimes % 60;
            strFinalScore = String.format(getString(R.string.result_content_add_minute), mCountCorrect, mCountWrong, minutes, seconds);
        } else {
            seconds = mTimes;
            strFinalScore = String.format(getString(R.string.result_content), mCountCorrect, mCountWrong, seconds);
        }
        SystemTTS.getInstance(this).speak(strFinalScore);

        bd.putString("score", strFinalScore);
        bd.putString("timeStamp", mTimeStamp);
        intent.putExtras(bd);
        startActivity(intent);
    }

    public void hideKeyboard() {
        InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(etInputResult.getWindowToken(), 0);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mTimer != null) {
            mTimer.cancel();
            mTimer = null;
        }
    }
}
